package com.sys.product.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sys.common.utils.PageUtils;
import com.sys.common.utils.Query;
import com.sys.product.dao.CategoryDao;
import com.sys.product.entity.CategoryEntity;
import com.sys.product.service.CategoryBrandRelationService;
import com.sys.product.service.CategoryService;
import com.sys.product.vo.Catalog2Vo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


@Service("categoryService")
public class CategoryServiceImpl extends ServiceImpl<CategoryDao, CategoryEntity> implements CategoryService {

    @Autowired
    CategoryBrandRelationService categoryBrandRelationService;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /*
     * 1.引用DAO可以不用注入，因为继承了ServiceImpl，baseMapper就是上面泛型指定的DAO
     *
     * 2.stream API
        //stream API(过滤出所有父分类 parentCid==0 )
        List<CategoryEntity> level1 = categoryEntities.stream().filter((one) -> {
            return one.getParentCid() == 0;
        }).collect(Collectors.toList());

        //stream API(简化版，如果方法体只有一行可以简化)
        List<CategoryEntity> level1 = categoryEntities.stream().filter(one ->
                one.getParentCid() == 0
        ).collect(Collectors.toList());
     * */
    @Override
    public List<CategoryEntity> listWithTree() {
        //查出所有分类
        List<CategoryEntity> allCategory = baseMapper.selectList(null);

        //根节点树
        List<CategoryEntity> allRootCategory = allCategory.stream().filter(one ->
                one.getParentCid() == 0
        ).map((one) -> {
            //通过map函数重新设置属性
            one.setChildren(getChild(one, allCategory));
            return one;
        }).sorted((s1, s2) -> {
            //通过sorted函数，给父节点排序
            return s1.getSort() - s2.getSort();
        }).collect(Collectors.toList());
        return allRootCategory;//返回根节点树
    }

    //递归查询此root节点下，所有子节点
    private List<CategoryEntity> getChild(CategoryEntity root, List<CategoryEntity> allCategory) {
        List<CategoryEntity> childList = allCategory.stream().filter(one -> {
            return one.getParentCid() == root.getCatId();
        }).map(one -> {
            one.setChildren(getChild(one, allCategory));
            return one;
        }).sorted((menu1, menu2) -> {
            return (menu1.getSort() == null ? 0 : menu1.getSort()) - (menu2.getSort() == null ? 0 : menu2.getSort());
        }).collect(Collectors.toList());
        return childList;
    }

    @Override
    public void removeMenunByIds(List<Long> catIds) {
        // TODO: 2021/6/4 删除前要注意其他地方有没有引用
        baseMapper.deleteBatchIds(catIds);
    }

    @Transactional//事务
    @Override
    public void updateCascate(CategoryEntity category) {
        this.updateById(category);
        //同时修改其他表冗余字段
        if (!StringUtils.isEmpty(category.getName())) {
            categoryBrandRelationService.updateCategoryName(category.getCatId(), category.getName());
        }
    }

    /*
     * 找到catelogId的完整路径：[3,2,1]
     * */
    @Override
    public Long[] findCategoryPath(Long categorygId) {
        List<Long> path = new LinkedList<>();
        findPath(categorygId, path);
        Collections.reverse(path);
        Long[] objects = path.toArray(new Long[path.size()]);
        return objects;
    }

    /*
     * 递归查找：
     * 1.判断是否有父节点
     * 2.有父节点就把父节点ID放到数组中，然后递归查上一个节点
     * */
    private void findPath(Long categorygId, List<Long> path) {
        if (categorygId != 0) {
            path.add(categorygId);
            CategoryEntity byId = getById(categorygId);
            findPath(byId.getParentCid(), path);
        }
    }

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<CategoryEntity> page = this.page(
                new Query<CategoryEntity>().getPage(params),
                new QueryWrapper()
        );
        return new PageUtils(page);
    }

    @Override
    public List<CategoryEntity> getLevel1Catagories() {
        long start = System.currentTimeMillis();
        List<CategoryEntity> parent_cid = this.list(new QueryWrapper<CategoryEntity>().eq("parent_cid", 0));
        System.out.println("查询一级菜单时间:" + (System.currentTimeMillis() - start));
        return parent_cid;
    }

    @Cacheable(value = {"category"}, key = "#root.methodName", sync = true)
    public Map<String, List<Catalog2Vo>> getCatalogJsonDbWithSpringCache() {
        return getCategoriesDb();
    }

    //从数据库中查出三级分类
    private Map<String, List<Catalog2Vo>> getCategoriesDb() {
        System.out.println("查询了数据库");
        //优化业务逻辑，仅查询一次数据库
        List<CategoryEntity> categoryEntities = this.list();
        //查出所有一级分类
        List<CategoryEntity> level1Categories = getCategoryByParentCid(categoryEntities, 0L);
        Map<String, List<Catalog2Vo>> listMap = level1Categories.stream().collect(Collectors.toMap(k -> k.getCatId().toString(), v -> {
            //遍历查找出二级分类
            List<CategoryEntity> level2Categories = getCategoryByParentCid(categoryEntities, v.getCatId());
            List<Catalog2Vo> catalog2Vos = null;
            if (level2Categories != null) {
                //封装二级分类到vo并且查出其中的三级分类
                catalog2Vos = level2Categories.stream().map(cat -> {
                    //遍历查出三级分类并封装
                    List<CategoryEntity> level3Catagories = getCategoryByParentCid(categoryEntities, cat.getCatId());
                    List<Catalog2Vo.Catalog3Vo> catalog3Vos = null;
                    if (level3Catagories != null) {
                        catalog3Vos = level3Catagories.stream()
                                .map(level3 -> new Catalog2Vo.Catalog3Vo(level3.getParentCid().toString(), level3.getCatId().toString(), level3.getName()))
                                .collect(Collectors.toList());
                    }
                    Catalog2Vo catalog2Vo = new Catalog2Vo(v.getCatId().toString(), cat.getCatId().toString(), cat.getName(), catalog3Vos);
                    return catalog2Vo;
                }).collect(Collectors.toList());
            }
            return catalog2Vos;
        }));
        return listMap;
    }

    private List<CategoryEntity> getCategoryByParentCid(List<CategoryEntity> categoryEntities, long l) {
        List<CategoryEntity> collect = categoryEntities.stream().filter(cat -> cat.getParentCid() == l).collect(Collectors.toList());
        return collect;
    }
}
